package com.xunai.saas.example.utils;

import com.xunai.saas.example.model.enums.PublicEnum;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/***
 * 请求工具类
 * @author Admin
 */
public class HttpClientUtils {

    private final static Logger log = LoggerFactory.getLogger(HttpClientUtils.class);

    public Map<String, String> headersMap;

    /***
     * 初始化headers 鉴权数据
     */ {
        //获取配置文件内容
        Properties properties = new Properties();
        InputStream in = HttpClientUtils.class.getClassLoader().getResourceAsStream("bootstrap.yml");
        try {
            properties.load(in);
        } catch (Exception e) {
            log.error("读取配置文件内容失败", e);
        }
        String secretId = properties.getProperty(PublicEnum.SECRET_ID.getKey());
        String secretKey = properties.getProperty(PublicEnum.SECRET_KEY.getKey());
        log.info("读取账户配置成功:secretId={},secretKey={}", secretId, secretKey);

        //示例为保证不会出现'签名过期'的异常,故固定时间戳.实际使用不建议这样设置.
        long timestamp = Tools.getTimestamp();
        //拼接组成sign
        String sign = secretId + timestamp + secretKey;
        sign = DigestUtils.md5DigestAsHex(sign.getBytes());
        //设置headers参数(接口鉴权参数)
        headersMap = new HashMap<>();
        headersMap.put("secretId", secretId);
        headersMap.put("timestamp", String.valueOf(timestamp));
        headersMap.put("sign", sign);
    }

    private final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /***
     * 证书相关
     */
    private static void trustAllHosts() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }
        }};
        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /***
     * 发起post请求
     * @param url   请求地址
     * @param params    参数对象
     * @return 请求结果
     */
    public String sendPost(String url, Object params) {
        // 构建请求参数
        String result = "";
        PrintWriter out = null;
        BufferedReader in = null;

        String sendString = "";
        //参数转json
        JSONObject json = JSONObject.fromObject(params);
        log.info("发送报文:" + json.toString());
        sendString = json.toString();

        try {
            trustAllHosts();
            URL url2 = new URL(url);

            HttpsURLConnection urlCon = (HttpsURLConnection) url2.openConnection();
            urlCon.setHostnameVerifier(DO_NOT_VERIFY);
            urlCon.setDoOutput(true);
            urlCon.setDoInput(true);
            urlCon.setRequestMethod("POST");
            urlCon.setRequestProperty("Content-type", "application/json;charset=UTF-8");
            //添加鉴权headers参数
            for (Map.Entry<String, String> map : headersMap.entrySet()) {
                urlCon.setRequestProperty(map.getKey(), map.getValue());
            }
            // 发送POST请求必须设置如下两行
            urlCon.setDoOutput(true);
            urlCon.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            OutputStream os = urlCon.getOutputStream();
            //参数是键值队  , 不以"?"开始
            os.write(sendString.getBytes());
            os.flush();
            // 发送请求参数
            //out.print(a);
            // flush输出流的缓冲
            //out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(urlCon.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {// 使用finally块来关闭输出流、输入流
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    /***
     * 发起get请求
     * @param sendUrl   请求地址
     * @return
     */
    public String sendGet(String sendUrl) {
        String result = null;
        // 默认配置创建一个httpClient实例
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建httpGet远程连接实例
        HttpGet httpGet = new HttpGet(sendUrl);
        //添加鉴权headers参数
        for (Map.Entry<String, String> map : headersMap.entrySet()) {
            httpGet.setHeader(map.getKey(), map.getValue());
        }
        // 设置配置请求参数
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(35000)// 连接主机服务超时时间
                .setConnectionRequestTimeout(35000)// 请求超时时间
                .setSocketTimeout(60000)// 数据读取超时时间
                .build();
        // 为httpGet实例设置配置
        httpGet.setConfig(requestConfig);
        try {
            // 执行get请求得到返回对象
            CloseableHttpResponse response = httpClient.execute(httpGet);
            // 通过返回对象获取返回数据
            HttpEntity entity = response.getEntity();
            // 通过EntityUtils中的toString方法将结果转换为字符串
            result = EntityUtils.toString(entity, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}
